package is.xdumper;

import is.bean.entity.department.Department;
import is.bean.entity.department.DepartmentBeanRemoteHome;
import is.bean.entity.employee.Employee;
import is.bean.entity.employee.EmployeeBeanRemoteHome;
import is.bean.entity.region.Region;
import is.bean.entity.region.RegionBeanRemoteHome;
import is.xdumper.type.Dump;
import java.rmi.RemoteException;
import java.util.*;
import javax.ejb.FinderException;
import nullutil.NullUtil;

/**
 * Collects entitys specified in index into dump and their references if needed
 *
 * @author aspr0
 */
public class XdumperDumpCollector
{
    private Dump dump;
    private DepartmentBeanRemoteHome departmentHome;
    private EmployeeBeanRemoteHome employeeHome;
    private RegionBeanRemoteHome regionHome;

    public Dump getDump()
    {
        return dump;
    }

    public void setDump(Dump dump)
    {
        this.dump = dump;
    }

    public void setDepartmentHome(DepartmentBeanRemoteHome departmentHome)
    {
        this.departmentHome = departmentHome;
    }

    public void setEmployeeHome(EmployeeBeanRemoteHome employeeHome)
    {
        this.employeeHome = employeeHome;
    }

    public void setRegionHome(RegionBeanRemoteHome regionHome)
    {
        this.regionHome = regionHome;
    }

    public void doCollect() throws FinderException, RemoteException
    {
        if (dump.getDumpReferences())
        {
            collectMajor();

            boolean refAdded;

            do
            {
                refAdded = false;

                if (collectParentRefs())
                {
                    refAdded = true;
                }
                if (collectDepartmentRefs())
                {
                    refAdded = true;
                }
                if (collectEmployeeRefs())
                {
                    refAdded = true;
                }
            }
            while (refAdded);
        }
        else
        {
            collectMajor();
        }
    }

    /**
     * Collects items for major entity table
     *
     * @throws FinderException
     * @throws RemoteException
     */
    private void collectMajor() throws FinderException, RemoteException
    {
        HashSet<Department> departmentTable = new HashSet<Department>();
        HashSet<Employee> employeeTable = new HashSet<Employee>();
        HashSet<Region> regionTable = new HashSet<Region>();

        switch (dump.getMajorEntity())
        {
            case DEPARTMENT:

                Iterator<Department> departments = dump.getDepartmentTable().iterator();

                while (departments.hasNext())
                {
                    Department department = departmentHome.findByPrimaryKey(departments.next().getId()).getData();
                    departmentTable.add(department);
                }
                break;

            case EMPLOYEE:

                Iterator<Employee> employees = dump.getEmployeeTable().iterator();

                while (employees.hasNext())
                {
                    Employee employee = employeeHome.findByPrimaryKey(employees.next().getId()).getData();
                    employeeTable.add(employee);
                }
                break;

            case REGION:

                Iterator<Region> regions = dump.getRegionTable().iterator();

                while (regions.hasNext())
                {
                    Region region = regionHome.findByPrimaryKey(regions.next().getId()).getData();
                    regionTable.add(region);
                }
                break;
        }

        dump.setDepartmentTable(departmentTable);
        dump.setEmployeeTable(employeeTable);
        dump.setRegionTable(regionTable);
    }

    /**
     * Collects inside-table parent references of entitys implementing HierarchyEntity.
     *
     * @return true if a replacement has been made
     */
    private boolean collectParentRefs() throws FinderException, RemoteException
    {
        Set<Department> departmentTable = dump.getDepartmentTable();
        Set<Region> regionTable = dump.getRegionTable();
        Iterator<Department> departments = departmentTable.iterator();
        Iterator<Region> regions = regionTable.iterator();

        /* For each cycle */
        boolean refAdded;
        /* For entire table. If at least one item added */
        boolean refAddedTotal = false;

        /* Searching for parent references till they are all added to the dump tables */
        do
        {
            refAdded = false;

            while (departments.hasNext())
            {
                Department department = departments.next();

                if (NullUtil.isPositiveInteger(department.getParentId()))
                {
                    Department parent = departmentHome.findByPrimaryKey(department.getParentId()).getData();

                    if (departmentTable.add(parent))
                    {
                        refAdded = true;
                        departments = departmentTable.iterator();
                    }
                }
            }

            while (regions.hasNext())
            {
                Region region = regions.next();

                if (NullUtil.isPositiveInteger(region.getParentId()))
                {
                    Region parent = regionHome.findByPrimaryKey(region.getParentId()).getData();

                    if (regionTable.add(parent))
                    {
                        refAdded = true;
                        regions = regionTable.iterator();
                    }
                }
            }

            if (refAdded)
            {
                refAddedTotal = true;
            }
        }
        while (refAdded);

        dump.setDepartmentTable(departmentTable);
        dump.setRegionTable(regionTable);

        return refAddedTotal;
    }

    /**
     * Collects cross-table references of Department entity
     *
     * @return true if a replacement has been made
     */
    private boolean collectDepartmentRefs() throws FinderException, RemoteException
    {
        Set<Department> departmentTable = dump.getDepartmentTable();
        Set<Employee> employeeTable = dump.getEmployeeTable();
        Set<Region> regionTable = dump.getRegionTable();
        Iterator<Department> departments = departmentTable.iterator();

        boolean refAdded = false;

        while (departments.hasNext())
        {
            Department department = departments.next();

            if (NullUtil.isPositiveInteger(department.getBossId()))
            {
                Employee boss = employeeHome.findByPrimaryKey(department.getBossId()).getData();

                if (employeeTable.add(boss))
                {
                    refAdded = true;
                }
            }

            Region region = regionHome.findByPrimaryKey(department.getRegionId()).getData();
            if (regionTable.add(region))
            {
                refAdded = true;
            }
        }

        dump.setEmployeeTable(employeeTable);
        dump.setRegionTable(regionTable);

        return refAdded;
    }

    /**
     * Collects cross-table references of Employee entity
     *
     * @return true if a replacement has been made
     */
    private boolean collectEmployeeRefs() throws FinderException, RemoteException
    {
        Set<Department> departmentTable = dump.getDepartmentTable();
        Set<Employee> employeeTable = dump.getEmployeeTable();
        Iterator<Employee> employees = employeeTable.iterator();

        boolean refAdded = false;

        while (employees.hasNext())
        {
            Employee employee = employees.next();
            Department department = departmentHome.findByPrimaryKey(employee.getDepartmentId()).getData();

            if (departmentTable.add(department))
            {
                refAdded = true;
            }
        }

        return refAdded;
    }
}
